﻿using System;
using System.IO;
using Ninject.Core;
using Odin.Contracts.Data;
using Odin.Contracts.Services;
using Odin.Execution.Utils;

namespace Odin.Execution.Services
{
	public class WebServer : IWebServer
	{
		public const string DevServerWindowTitle = "ASP.NET Development Server";
		public const string ApplicationToTestRelativePath = @"ClientBin\ApplicationToTest";
		private const string DevServerPath = @"Microsoft Shared\DevServer\9.0";
		private const string DevServerExecutable = "WebDev.WebServer.EXE";
		


		public WebServer()
		{
		}

		#region Injected properties
		[Inject]
		public IWindowService WindowService { get; set; }

		[Inject]
		public IProcessService ProcessService { get; set; }

		[Inject]
		public IConfiguration Configuration { get; set; }
		#endregion


		public void ShutDown()
		{
			var window = GetHostWindow();
			if (null != window)
			{
				ProcessService.Kill(window.ProcessId);
			}
		}

		public string BaseUrl
		{
			get
			{
				var url = string.Format("http://localhost:{0}", Port);
				return url;
			}
		}

		public string ApplicationToTestPath
		{
			get
			{
				var path = string.Format("{0}\\{1}", Configuration.WebServer.PhysicalPath, ApplicationToTestRelativePath);
				return path;
			}
		}
		public int Port { get; private set; }


		public void EnsureHostIsRunning()
		{
			if (Configuration.WebServer.Port != -1)
			{
				Port = Configuration.WebServer.Port;
			}
			else
			{
				Port = SocketHelper.GetAvailablePort();
			}

			if (!IsHostRunning())
			{
				StartHost();
			}
		}

		public void ClearDirectory()
		{
			if (!Directory.Exists(ApplicationToTestPath))
			{
				Directory.CreateDirectory(ApplicationToTestPath);
			}
			else
			{
				var files = Directory.GetFiles(ApplicationToTestPath);
				foreach (var file in files)
				{
					File.Delete(file);
				}
			}
		}

		public void PrepareDirectory(Session session)
		{

		}

		public void PrepareRunner(Session session)
		{
			var destinationFilename = string.Format("{0}\\{1}", ApplicationToTestPath, Path.GetFileName(session.XapPath));
			if (!File.Exists(session.XapPath))
			{
				throw new ArgumentException(string.Format("File '{0}' does not exist",session.XapPath));
			}
			var directory = Path.GetDirectoryName(destinationFilename);
			if( !Directory.Exists(directory))
			{
				throw new DirectoryNotFoundException(directory);
			}
			File.Copy(session.XapPath, destinationFilename);
		}


		public bool IsHostRunning()
		{
			var window = GetHostWindow();
			return null != window;
		}


		#region Private Helper methods
		private IWindow GetHostWindow()
		{
			var windows = WindowService.GetWindowsStartingWith(DevServerWindowTitle);
			foreach (var window in windows)
			{
				var index = window.Title.IndexOf("Port");
				var portIndex = index + 5;
				var port = Int32.Parse(window.Title.Substring(portIndex));
				if (port == Port)
				{
					return window;
				}
			}
			return null;
		}

		private void StartHost()
		{
			var commonFilesPath = Environment.GetFolderPath(Environment.SpecialFolder.CommonProgramFiles);
			var fullPath = string.Format("{0}\\{1}", commonFilesPath, DevServerPath);
			var filename = string.Format("{0}\\{1}", fullPath, DevServerExecutable);
			var arguments = string.Format("/port:{0} /path:\"{1}\"", Port, Configuration.WebServer.PhysicalPath);
			ProcessService.Start(filename, arguments);
		}
		#endregion
	}
}